/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_real_constraint.cpp                                                *
 ****************************************************************************/


#include "elisa_real_constraint.h"


USING_ELISA


//--------------------------------------------------------------------------
// class RealConstraintRep
//--------------------------------------------------------------------------
RealConstraintRep::RealConstraintRep (const std::string & rel, bool prefix)
	: _prefix(prefix), _rel(rel)
{
	m_nref = 0;
}

RealConstraintRep::RealConstraintRep (const RealConstraintRep & c)
	: ConstraintRep(c),
	  _prefix(c._prefix), _rel(c._rel)
{
	m_nref = 0;
}

RealConstraintRep::~RealConstraintRep()
{
	/*
 	   for (unsigned int i = 0; i < _exprs.size(); ++i)
 	   {
 	   delete _exprs[i];
 	   }
 	 */
}

void RealConstraintRep::print(std::ostream & os) const
{
	if (_prefix) {
		os << _rel << "(";

		for (unsigned int i = 0; i < m_exprs.size(); ++i) {
			m_exprs[i]->print(os);
			if (i < (m_exprs.size() - 1)) {
				os << ',';
			}
		}
		os << ")";
	} else {
		unsigned int i = 0;
		do {
			m_exprs[i]->print(os);
			if (i < (m_exprs.size() - 1)) {
				os << _rel;
			}
			++i;
		} while (i < m_exprs.size());
	}
}


//--------------------------------------------------------------------------
// class RealConstraintVisitor
//--------------------------------------------------------------------------
RealConstraintVisitor::RealConstraintVisitor()
{
}

RealConstraintVisitor::~RealConstraintVisitor()
{
}


//--------------------------------------------------------------------------
// class RealConstraintBinaryRep
//--------------------------------------------------------------------------
RealConstraintBinaryRep::RealConstraintBinaryRep (RealExpr *l, RealExpr *r,
                                                  const std::string & rel)
	: RealConstraintRep(rel, false)
{
	addExpr(l);
	addExpr(r);
}

RealConstraintBinaryRep::~RealConstraintBinaryRep ()
{
}

RealExpr *RealConstraintBinaryRep::left()
{
	return dynamic_cast<RealExpr *>(m_exprs[0].get());
}

RealExpr *RealConstraintBinaryRep::const_left() const
{
	return dynamic_cast<RealExpr *>(m_exprs[0].get());
}

RealExpr *RealConstraintBinaryRep::right()
{
	return dynamic_cast<RealExpr *>(m_exprs[1].get());
}

RealExpr *RealConstraintBinaryRep::const_right() const
{
	return dynamic_cast<RealExpr *>(m_exprs[1].get());
}


//--------------------------------------------------------------------------
// class RealConstraintRepEq
//--------------------------------------------------------------------------
RealConstraintRepEq::RealConstraintRepEq (RealExpr *l,      // left expression
                                          RealExpr *r)      // right expression
	: RealConstraintBinaryRep(l, r, "==")
{
}


RealConstraintRepEq::RealConstraintRepEq (const RealConstraintRepEq & c)
	: RealConstraintBinaryRep(new RealExpr(*c.const_left()), new RealExpr(*c.const_right()), "==")
{
}

RealConstraintRepEq::~RealConstraintRepEq ()
{
}

void RealConstraintRepEq::visit(RealConstraintVisitor & v)
{
	v.visited(*this);
}

RealConstraintRep *RealConstraintRepEq::copy() const
{
	return new RealConstraintRepEq(const_left()->copy(),
	                               const_right()->copy());
}

RealExpr *RealConstraintRepEq::function() const
{
	return new RealExpr((*const_left()) - (*const_right()));
}

//RealConstraintRepEq&
//RealConstraintRepEq::operator=(const RealConstraintRepEq& c) {}



//--------------------------------------------------------------------------
// class RealConstraintRepInf
//--------------------------------------------------------------------------
RealConstraintRepInf::RealConstraintRepInf(RealExpr *l, // left expression
                                           RealExpr *r) // right expression
	: RealConstraintBinaryRep(l, r, "<=")
{}

RealConstraintRepInf::RealConstraintRepInf (const RealConstraintRepInf & c) :
	RealConstraintBinaryRep(new RealExpr(*c.const_left()), new RealExpr(*c.const_right()), "<=")
{}

RealConstraintRepInf::~RealConstraintRepInf ()
{
}

void RealConstraintRepInf::visit(RealConstraintVisitor & v)
{
	v.visited(*this);
}

RealConstraintRep *RealConstraintRepInf::copy() const
{
	return new RealConstraintRepInf(const_left()->copy(),
	                                const_right()->copy());
}

RealExpr *RealConstraintRepInf::function() const
{
	return new RealExpr((*const_left()) - (*const_right()));
}

//RealConstraintRepInf&
//RealConstraintRepInf::operator=(const RealConstraintRepInf& c) {}



//--------------------------------------------------------------------------
// class RealConstraintRepSup
//--------------------------------------------------------------------------
RealConstraintRepSup::RealConstraintRepSup (RealExpr *l,      // left expression
                                            RealExpr *r) :     // right expression
	                                                           RealConstraintBinaryRep(l, r, ">=")
{
}

RealConstraintRepSup::RealConstraintRepSup (const RealConstraintRepSup & c) :
	RealConstraintBinaryRep(new RealExpr(*c.const_left()),
	                        new RealExpr(*c.const_right()),
	                        ">=")
{
}

RealConstraintRepSup::~RealConstraintRepSup ()
{
}

void RealConstraintRepSup::visit(RealConstraintVisitor & v)
{
	v.visited(*this);
}

RealConstraintRep *RealConstraintRepSup::copy() const
{
	return new RealConstraintRepSup(const_left()->copy(),
	                                const_right()->copy());
}

RealExpr *RealConstraintRepSup::function() const
{
	return new RealExpr((*const_left()) - (*const_right()));
}

//RealConstraintRepSup&
//RealConstraintRepSup::operator=(const RealConstraintRepSup& c) {}



//--------------------------------------------------------------------------
// class RealConstraint
//--------------------------------------------------------------------------

RealConstraint::RealConstraint() 
: Constraint(new RealConstraintRepEq(new RealExpr, new RealExpr))
{
	dynamic_cast<RealConstraintRep *>(m_rep)->addRef();
}

RealConstraint::RealConstraint(RealConstraintRep & c) 
: Constraint(&c)
{
	c.addRef();
}

RealConstraint::RealConstraint(RealConstraintRep *c) 
: Constraint(c)
{
	c->addRef();
}

RealConstraint::RealConstraint(const RealConstraint & c) 
: Constraint(c)
{
	dynamic_cast<RealConstraintRep *>(c.m_rep)->addRef();
}

RealConstraint::~RealConstraint()
{
	dynamic_cast<RealConstraintRep *>(m_rep)->delRef();
}

RealConstraint & RealConstraint::operator=(const RealConstraint & c)
{
	dynamic_cast<RealConstraintRep *>(m_rep)->delRef();
	m_rep = c.m_rep;
	dynamic_cast<RealConstraintRep *>(m_rep)->addRef();
	m_vars.clear();
	return *this;
}

RealConstraintRep *RealConstraint::copyRep() const
{
	return dynamic_cast<RealConstraintRep *>(m_rep)->copy();
}

RealConstraintRep *RealConstraint::rep()
{
	return dynamic_cast<RealConstraintRep *>(m_rep);
}

const RealConstraintRep *RealConstraint::const_rep() const
{
	return dynamic_cast<RealConstraintRep *>(m_rep);
}


RealExpr *RealConstraint::function() const
{
	return dynamic_cast<RealConstraintRep *>(m_rep)->function();
}


//--------------------------------------------------------------------------
// Operators
//--------------------------------------------------------------------------

elisa::RealConstraint operator==(const elisa::RealExpr & l, 
								 const elisa::RealExpr & r)
{
	return RealConstraint(new elisa::RealConstraintRepEq(new elisa::RealExpr(l),
	                                                     new elisa::RealExpr(r)));
}

elisa::RealConstraint operator<=(const elisa::RealExpr & l,
					             const elisa::RealExpr & r)
{
	return RealConstraint(new elisa::RealConstraintRepInf(new elisa::RealExpr(l),
	                                                      new elisa::RealExpr(r)));
}

elisa::RealConstraint operator>=(const elisa::RealExpr & l,
								 const elisa::RealExpr & r)
{
	return RealConstraint(new elisa::RealConstraintRepSup(new elisa::RealExpr(l),
	                                                      new elisa::RealExpr(r)));
}
